﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Kaidou.Model;
using Kaidou.Util;
using System.Runtime.CompilerServices;
using System.Data;
using System.Data.SqlClient;

namespace Kaidou.Persister
{
    public class NextSealNoSequencePersister
    {


        /** Singleton Instance */
        private static NextSealNoSequencePersister instance = new NextSealNoSequencePersister();
        /** 排他処理のためのフラグ */
        private static bool locked = false;

        /**
         * デフォルトコンストラクタ
         */
        private NextSealNoSequencePersister()
        {
        }

        /**
         * 処理の開始時に Instance を取得し、ロックする
         *
         * @return このクラスの Singleton Instance. 他で使用中のときは５秒間待ってから例外を返す
         */
        public static NextSealNoSequencePersister checkout()
        {
            try
            {
                for (int i = 0; i < 25; i++)
                {
                    if (!locked)
                    {
                        locked = true;
                        return instance;
                    }
                    Thread.Sleep(400);
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            throw new Exception("Failed to get seal No. Couldn't lock the class.");
        }

        /**
         * 処理終了後にロックを解除する
         */
        public static void checkin()
        {
            locked = false;
        }

        /*
         * 廃止.
         *
         * Nextval_purch_seal_no_proc をコールし、一気にシール番号用のシーケンスを取得する.
         * 自動 rollback が効かないため、catch 節にこのクラスの rollback() を記述すること
         *
         * @param con
         * @param count シーケンス確保枚数
         * @return int 確保できた場合の開始番号
         * @throws PersisterSQLException
        private NextSealNoSequenceModel NextvalProcedureSource(Connection con, int count) throws PersisterSQLException {
	
            Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " NextvalProcedure in --------------------------- ");
            Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " in count=" + count);
	
            NextSealNoSequenceModel model = null;
	
            CallableStatement callStmt = null;
	
            String procName = "Nextval_purch_seal_no_proc";
            String sql = "CALL " + procName + "( ?, ?, ?, ?, ? )";
	
            try {
                callStmt = con.prepareCall(sql);
	
                callStmt.setInt(1, count);
                callStmt.registerOutParameter(2, Types.INTEGER);
                callStmt.registerOutParameter(3, Types.INTEGER);
                callStmt.registerOutParameter(4, Types.INTEGER);
                callStmt.registerOutParameter(5, Types.VARCHAR);
	
                callStmt.execute();
	
                int outErrorCode = callStmt.getInt(4);
                String outErrorMsg = callStmt.getString(5);
	
                model = new NextSealNoSequenceModel();
                model.setStart_No(callStmt.getInt(2));
                model.setEnd_No(callStmt.getInt(3));
                Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " get Nextval_purch_seal_no_proc: start_no=" + model.getStart_No() + " end_no=" + model.getEnd_No());
                Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " From Nextval_purch_seal_no_proc back sqlCode=" + outErrorCode + " returnString = [" + outErrorMsg + "]");
                if (outErrorCode != 0) {
                    Logger.logWrite(NextSealNoSequencePersister.class.getName(), "F", " insert - CallableStatement close sql_code = " + outErrorCode + " returnString = [" + outErrorMsg + "]");
                    throw new PersisterSQLException(new SQLException(" Nextval_purch_seal_no_proc error "));
                }
                callStmt.close();
                Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " NextvalProcedure out --------------------------- ");
            } catch (SQLException e) {
                throw new PersisterSQLException(e);
            } finally {
                try {
                    callStmt.close();
                } catch (Exception e) {
                    Logger.logWrite(NextSealNoSequencePersister.class.getName(), "F", " insert - CallableStatement close ", e);
                }
            }
            return model;
        }
         */

        /**
         * シールの開始番号を sequence から取得する
         *
         * @param con
         * @param count
         * @return 
         * @throws PersisterSQLException
         * @throws FrameworkException
         */
        [MethodImpl(MethodImplOptions.Synchronized)]
        public NextSealNoSequenceModel NextvalProcedure(SqlDB con)
        {
            if (!locked)
            {
                throw new Exception("The class is not locked.");
            }

            //Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " NextvalProcedure in --------------------------- ");

            NextSealNoSequenceModel model = new NextSealNoSequenceModel();

            //String sql = "select Proc_SEAL_NO_SEQ_ZB(" + System.DateTime.Now.ToString("yy") + ")";


            string sql = "Proc_SEAL_NO_SEQ_ZB";

            SqlParameter[] sqlParameter = { new SqlParameter("@in_yy", SqlDbType.VarChar, 2), new SqlParameter("@return", SqlDbType.Int) };
            sqlParameter[0].Value = System.DateTime.Now.ToString("yy");
            sqlParameter[1].Direction = ParameterDirection.ReturnValue;


            try
            {

                con.ExecuteProcedure(sql, ref sqlParameter);

                int seqno = int.Parse(sqlParameter[1].Value.ToString());

                model.setStart_No(seqno);
                //Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " get Nextval_purch_seal_no_proc: start_no=" + model.getStart_No() + " end_no=" + model.getEnd_No());
                //Logger.logWrite(NextSealNoSequencePersister.class.getName(), "D", " NextvalProcedure out --------------------------- ");
            }
            catch (Exception e)
            {
                throw e;
            }
            return model;
        }

        /**
         * 確認シール番号の sequence を targetNo にセットして restart する.
         * "0" が渡されたときは何もしない
         *
         * @param con
         * @param targetNo
         * @throws PersisterSQLException
         */
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void restartSealNoSequence(SqlDB con, int targetNo)
        {
            if (targetNo == 0)
            {
                return;
            }

            String sql = "update SEAL_NO_SEQ_ZB Set sid=" + targetNo + " Where syy='" + System.DateTime.Now.ToString("yy") + "'";
            try
            {
                con.ExecuteCmd(sql, null);

            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /*
         * Nextval_purch_seal_no_proc をコールして開始番号を取得し、さらに枚数から終了番号を取得する.
         * 自動 rollback が効かないため、catch 節にこのクラスの rollback() を記述すること
         *
         * @param con
         * @param count シーケンス確保枚数
         * @return int 確保できた場合の開始番号
         * @throws PersisterSQLException
         * @throws FrameworkException
        public NextSealNoSequenceModel NextvalProcedure1(Connection con, int count) throws PersisterSQLException, FrameworkException {
            if (!locked) {
                throw new FrameworkException("The class is not locked.");
            }

            if (count == 0) {
                throw new PersisterSQLException(new SQLException("New seal count must be greater than 0."));
            }

            NextSealNoSequenceModel sourceModel = new NextSealNoSequenceModel();
            try {
                // 開始番号だけ取得する
                sourceModel = NextvalProcedure(con);
            } catch (PersisterSQLException e) {
                // rollback不要
                throw new PersisterSQLException(e.getSQLException());
            }

            NextSealNoSequenceModel model = new NextSealNoSequenceModel();
            model.setStart_No(sourceModel.getStart_No());

            // 開始番号と枚数から終了番号を取得する
            SimpleDateFormat sdf = new SimpleDateFormat("yy");
            String sql = "alter sequence SEAL_NO_" + sdf.format(new java.util.Date()) + "_SEQ RESTART with " + sourceModel.getStart_No() + count;
            try {
                PreparedStatement stmt = con.prepareStatement(sql);
                try {
                    stmt.execute();
                } finally {
                    stmt.close();
                }
                //throw new SQLException("test");
            } catch (SQLException e) {
                restartSealNoSequence(con, sourceModel.getStart_No());
                throw new PersisterSQLException(e);
            }

            return model;
        }
         */

    }
}
